﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MathNet.Numerics.LinearAlgebra;
using System.IO;
using System.Drawing.Imaging;
using System.Runtime.Serialization.Formatters.Binary;

namespace ImgProcessGui
{
    public partial class Form1 : Form
    {
      
        String[] Files2Show = new string[3];
        Histograma.HistogramaControl[] HistArray = new Histograma.HistogramaControl[11];
        PictureBox[] PicBoxArray = new PictureBox[10];
        //This dictionary contains file-name & norm
        Dictionary<string, double> results = new Dictionary<string, double>();

               //TODO - Move To GuiParameters.cs
        public void CopyDataFromGui()
        {
            GuiParameters.patch_H = System.Convert.ToInt32(txtPatchDim.Text);
            GuiParameters.patch_W = System.Convert.ToInt32(txtPatchDim.Text);//TODO-Remove (we assume rectengular patches) 
            GuiParameters.num_Of_Init_Centers = System.Convert.ToInt32(txtInitCenters.Text);
            GuiParameters.data_Depth = System.Convert.ToInt32(txtDepthOfData.Text);
            GuiParameters.limit_K_Mean = System.Convert.ToInt32(txtLimitKMean.Text);
            GuiParameters.jump_Size = System.Convert.ToInt32(txtJumpSize.Text);
            GuiParameters.isRGB = checkBox3.Checked;
            GuiParameters.toScale = checkBox5.Checked;
            GuiParameters.rGBFactor = Convert.ToDouble(txtRGBFactor.Text);
        }

        public Form1()
        {
            InitializeComponent();
            //Creating Array to handle Histograms
            HistArray[0] = histogramaControl1;
            HistArray[1] = histogramaControl2;
            HistArray[2] = histogramaControl3;
            HistArray[3] = histogramaControl4;
            HistArray[4] = histogramaControl5;
            HistArray[5] = histogramaControl6;
            HistArray[6] = histogramaControl7;
            HistArray[7] = histogramaControl8;
            HistArray[8] = histogramaControl9;
            HistArray[9] = histogramaControl10;
            HistArray[10] = histogramaControl11;
            //Creating Array to handle pictureBox
            PicBoxArray[0] = pictureBox1;
            PicBoxArray[1] = pictureBox2;
            PicBoxArray[2] = pictureBox3;
            PicBoxArray[3] = pictureBox4;
            PicBoxArray[4] = pictureBox5;
            PicBoxArray[5] = pictureBox6;
            PicBoxArray[6] = pictureBox7;
            PicBoxArray[7] = pictureBox8;
            PicBoxArray[8] = pictureBox9;
            PicBoxArray[9] = pictureBox10;

        }
        
        #region Logic Flows Control (Buttons)
        
        private void btnCreateDictionary_Click(object sender, EventArgs e)
        {
            CopyDataFromGui();
            //=============================================================================================
            ImageFunctions ImageFunctionsAlgorithems = new ImageFunctions();
            Algorithems ImageProceesAlgorithems = new Algorithems();
            MatrixFunctions matFunc = new MatrixFunctions();
            
            //*********************************Create Ditionary***********************************************
            //byte[] data = ImageFunctionsAlgorithems.getPicturesPatches(@".\PicTest", GuiParameters.patch_H, GuiParameters.jump_Size);
            Matrix data_GreyScale;
            Matrix data_RGB_PatchAvg;

            byte[] data = ImageFunctionsAlgorithems.getPicturesPatches(@"C:\Program Files\IdentifierFiles\PicsToCreateDictionary", GuiParameters.patch_H, GuiParameters.jump_Size, out data_GreyScale, out data_RGB_PatchAvg);
            #region Creating Random Centers
            Matrix inicenters = new Matrix(GuiParameters.data_Depth+3, GuiParameters.num_Of_Init_Centers);//TODO - Remove + 3 for grey
            Random rnd = new Random();
            for (int cntr = 0; cntr < GuiParameters.num_Of_Init_Centers; cntr++)
            {
                for (int pnt = 0; pnt < GuiParameters.data_Depth; pnt++)
                {
                    if (checkBox5.Checked)
                    {
                        inicenters[pnt, cntr] = (rnd.NextDouble() * 16.0) - 8.0;
                    }
                    else
                    {
                        inicenters[pnt, cntr] = (rnd.NextDouble() * 510.0) - 255.0;
                    }

                }
                for (int pnt = GuiParameters.data_Depth; pnt < GuiParameters.data_Depth+3; pnt++) // For RGB Tail
                {
                        inicenters[pnt, cntr] = (rnd.NextDouble() * 255.0)*GuiParameters.rGBFactor;                   
                }
            }
            #endregion
            
            Matrix pcaDic;
            Matrix pcaEigenVectors;
            
            #region Proccesing & saving data
            ImageProceesAlgorithems.processData(data, GuiParameters.patch_H * GuiParameters.patch_H, GuiParameters.data_Depth, GuiParameters.num_Of_Init_Centers, GuiParameters.limit_K_Mean, true, inicenters, out pcaDic, out pcaEigenVectors, data_GreyScale, data_RGB_PatchAvg); 

            matFunc.SaveMatrix("Dictionary", "DicPixeled", pcaDic);
            matFunc.SaveMatrix("Dictionary", "EigenVectors", pcaEigenVectors);
            matFunc.PrintMatToFile(pcaDic.GetArray(), "DictionPixeled");
            #endregion
        }

        private void btnCreateHistograms_Click(object sender, EventArgs e)
        {
            GuiParameters.jump_Size = System.Convert.ToInt32(txtJumpSize.Text);
            GuiParameters.patch_H = System.Convert.ToInt32(txtPatchDim.Text);
            GuiParameters.data_Depth = System.Convert.ToInt32(txtDepthOfData.Text);
            GuiParameters.isRGB = checkBox3.Checked;
            GuiParameters.toScale = checkBox5.Checked;
            GuiParameters.rGBFactor = Convert.ToDouble(txtRGBFactor.Text);
            ImageFunctions ImageFunctionsAlgorithems = new ImageFunctions();
            Algorithems ImageProceesAlgorithems = new Algorithems();
            MatrixFunctions matFunc = new MatrixFunctions();

            Matrix dictionaryPcaMat;
            matFunc.LoadMatrix("Dictionary", "DicPixeled", out dictionaryPcaMat);
            //summing histograms from all files will allow us to evetually remove the highest bin
            Vector histograms = Vector.Zeros(dictionaryPcaMat.ColumnCount);
            //iterating over files creating their histograms
            String[] files = Directory.GetFiles(@"C:\Program Files\IdentifierFiles\PicTest", @"*.bmp");
            progressBar1.Maximum = files.Length;
            foreach(String fileName in files)
            {
                histograms += ImageProceesAlgorithems.createHistogram("PicTest", fileName, dictionaryPcaMat, GuiParameters.jump_Size);
                progressBar1.Value += 1;
            }
            //find and save most used word

            Max_Bins_Positions maxBins = findHighest(histograms);

            progParametes.Instance.FirstwordToIgnore = maxBins.highestMaxPostion;
            progParametes.Instance.SecondwordToIgnore = maxBins.secondMaxPostion;
            progParametes.Instance.Save();
            progressBar1.Value = 0;
        }

        private void btnIdentifyPicure_Click(object sender, EventArgs e)
        {
            GuiParameters.jump_Size = System.Convert.ToInt32(txtJumpSize.Text);
            GuiParameters.patch_H = System.Convert.ToInt32(txtPatchDim.Text);
            GuiParameters.data_Depth = System.Convert.ToInt32(txtDepthOfData.Text);
            GuiParameters.isRGB = checkBox3.Checked;
            GuiParameters.toScale = checkBox5.Checked;
            ImageFunctions ImageFunctionsAlgorithems = new ImageFunctions();
            Algorithems ImageProceesAlgorithems = new Algorithems();
            MatrixFunctions matFunc = new MatrixFunctions();
            results.Clear();
            if (checkBox4.Checked == true)
            {
                UpdateBinToRemove();
            }
                        
            Matrix TestMat;
            Vector TestHit;
            Matrix dictionaryMat;
            matFunc.LoadMatrix("Dictionary", "DicPixeled", out dictionaryMat);
            String[] now = Directory.GetFiles(@"C:\Program Files\IdentifierFiles\Pic2Classify");
            picBoxPic2Identify.Load(now[0]);
            //Creating Pic2Classify Histogram
            Vector Pic2ClassifyHist = ImageProceesAlgorithems.createHistogram("Pic2Classify", now[0], dictionaryMat, GuiParameters.jump_Size);
            String[] files = Directory.GetFiles(@"C:\Program Files\IdentifierFiles\PicTest", "*.dat");
            progressBar1.Maximum = files.Length;
            double[] tableOfNorms = new double[files.Length];
            double norm4Test = 0;
            Norm norm = new Norm();
            TextWriter writer = new StreamWriter(@"C:\Program Files\IdentifierFiles\PicTest\reults.csv");
            
            int counter = 0;
            if (checkBox1.Checked == true)
            {
                Pic2ClassifyHist[progParametes.Instance.FirstwordToIgnore] = 0;
            }
            if (checkBox2.Checked == true)
            {
                Pic2ClassifyHist[progParametes.Instance.SecondwordToIgnore] = 0;
            }
            
            PlotHistogram(Pic2ClassifyHist,0);
            
            //Comparing Histograms and writing to file: PicTest\reults.log
            foreach(String fileName in files)
            {
                
                BinaryFormatter bf = new BinaryFormatter();
                FileStream reader = new FileStream(fileName, FileMode.Open);
                TestMat = new Matrix((double[][])bf.Deserialize(reader));
                reader.Close();
                TestHit = TestMat.GetRowVector(0);
                if(checkBox1.Checked==true)
                {
                    TestHit[progParametes.Instance.FirstwordToIgnore] = 0;   
                }
                if (checkBox2.Checked == true)
                {
                    TestHit[progParametes.Instance.SecondwordToIgnore] = 0;
                }
                
                norm4Test = norm.Norm1(Pic2ClassifyHist, TestHit);
                tableOfNorms[counter] = norm4Test;
                String[] seperators = new String[2];
                seperators[0]=@"\";
                seperators[1] = @"_";
                String[] parsedFileName = fileName.Split(seperators,StringSplitOptions.None);
                //Adding results to dictionary
                results.Add(fileName, norm4Test);
                writer.Write(parsedFileName[4] + "," + parsedFileName[5] + "," + Convert.ToString(norm4Test));
                writer.WriteLine();
                counter++;
                progressBar1.Value += 1;
            }
            //Adding Results to DataGrid----------------------------------------------------------------------
            List<KeyValuePair<string, double>> resultsList = SortResults.SortDictionary(results);
            dgResults.DataSource = resultsList;
            writer.Close();
            progressBar1.Value = 0;
        }

        private void btnShowDictionary_Click(object sender, EventArgs e)
        {
            Matrix dictionaryMat;
            Matrix pcaEigenVectors;
            ImageFunctions ImageFunctionsAlgorithems = new ImageFunctions();
            MatrixFunctions matFunc = new MatrixFunctions();
            CopyDataFromGui();
            matFunc.LoadMatrix("Dictionary", "DicPixeled", out dictionaryMat);
            matFunc.LoadMatrix("Dictionary", "EigenVectors", out pcaEigenVectors);
            //Recovering Dictionary for plot
            Matrix recoveredData = pcaEigenVectors * dictionaryMat;
            byte[] dicInBytes = ImageFunctionsAlgorithems.Matrix2Byte(recoveredData);
            Bitmap dicBmp;
            
            if(GuiParameters.isRGB)
            {
                dicBmp = ImageFunctionsAlgorithems.CreateBMPDictionaryRGB(dicInBytes, GuiParameters.patch_H);
            }
            else
            {
                dicBmp = ImageFunctionsAlgorithems.CreateBMPDictionary(dicInBytes, GuiParameters.patch_H);
            }
                      
            dicBmp.Save(@"C:\Program Files\IdentifierFiles\Dictionary\dic.bmp");
            pictBoxDictionary.Load(@"C:\Program Files\IdentifierFiles\Dictionary\dic.bmp");
        }

        private void btnRUN_Click(object sender, EventArgs e)
        {

            Matrix a = new Matrix(2, 2);
            Matrix b = new Matrix(3,2);
            a[0, 0] = 1; a[0, 1] = 2; a[1, 0] = 3; a[1, 1] = 4;
            b[0, 0] = 7; b[0, 1] = 7; b[1, 0] = 8; b[1, 1] = 8; b[2, 0] = 9; b[2, 1] = 10;
            a  =MatrixFunctions.GlueMatrixUpToDown(a, b);
            //Matrix f = MatrixFunctions.GlueMatrixSideBySide(a, d);
            
        }

      

        private void btnTestFunctions_Click(object sender, EventArgs e)
        {
            Matrix matTest = new Matrix(3,3);
            Matrix cenTest = new Matrix(3, 2);
            Algorithems kmean = new Algorithems();
            for (int i = 0; i < matTest.ColumnCount; i++)
            {
                matTest[0, i] = -i;
                matTest[1, i] = -i;
                matTest[2, i] = -i;
            }
            for (int i = 0; i < cenTest.ColumnCount; i++)
            {
                cenTest[0, 0] = -0.2;
                cenTest[1, 0] = -0.2;
                cenTest[2, 0] = -0.2;
                cenTest[0, 1] = -8;
                cenTest[1, 1] = -8;
                cenTest[2, 1] = -8;          
            }
            Matrix result = kmean.K_Mean(matTest, cenTest, 100);

        }

        #endregion

        #region private methods

        private void PlotHistogram(Vector Pic2ClassifyHist, int HistogramNumber)
        {
            double[] HistPicDouble = Pic2ClassifyHist.CopyToArray();
            long[] HistPicLong = new long[HistPicDouble.Length];
            for (int i = 0; i < HistPicDouble.Length; i++)
            {
                HistPicLong[i] = (long)(HistPicDouble[i]*10000);
            }
            HistArray[HistogramNumber].DrawHistogram(HistPicLong);
        }
        
        /// <summary>
        /// updating bin to remove if histograms somehow changed 
        /// </summary>
        public void UpdateBinToRemove()
        {
            String[] files;
            Matrix dictionaryMat;
            MatrixFunctions matFunc = new MatrixFunctions();
            matFunc.LoadMatrix("Dictionary", "DicPixeled", out dictionaryMat);
            
            if (checkBox6.Checked == true)
            {
                //Removing highest bins from pic2classify
                files = Directory.GetFiles(@"C:\Program Files\IdentifierFiles\Pic2Classify", "*.dat");
            }
            else
            {
                files = Directory.GetFiles(@"C:\Program Files\IdentifierFiles\PicTest", "*.dat");
            }
            
            Vector histograms = Vector.Zeros(dictionaryMat.ColumnCount);   
            foreach (String fileName in files)
            {
                BinaryFormatter bf = new BinaryFormatter();
                FileStream reader = new FileStream(fileName, FileMode.Open);
                Matrix TestMat = new Matrix((double[][])bf.Deserialize(reader));
                reader.Close();
                Vector TestHit = TestMat.GetRowVector(0);
                histograms += TestHit;
            }
            Max_Bins_Positions maxBins = findHighest(histograms);
            progParametes.Instance.FirstwordToIgnore = maxBins.highestMaxPostion;
            progParametes.Instance.SecondwordToIgnore = maxBins.secondMaxPostion;
            progParametes.Instance.Save();
        }
      

        /// <summary>
        /// return position of the 2 highest bins in the vector
        /// </summary>
        /// <param name="DataVec"></param>
        /// <returns></returns>
        private Max_Bins_Positions findHighest(Vector DataVec)
        {
            Max_Bins_Positions maxPositions;
            double max = 0;
            maxPositions.highestMaxPostion  = 0;
            maxPositions.secondMaxPostion = 0;
            //Finding highest Bin
            for (int i = 0; i < DataVec.Length; i++)
            {
                if (DataVec[i] > max)
                {
                    max = DataVec[i];
                    maxPositions.highestMaxPostion = i;
                }
            }
            //Finding Second highest Bin
            max = 0;
            for (int i = 0; i < DataVec.Length; i++)
            {
                if (i != maxPositions.highestMaxPostion)
                {
                    if (DataVec[i] > max)
                    {
                        max = DataVec[i];
                        maxPositions.secondMaxPostion = i;
                    }
                }
            }
            return maxPositions;         
        }

      

        
        #endregion

        #region private Members & Enums
        private struct Max_Bins_Positions
        {
            public int highestMaxPostion;
            public int secondMaxPostion;
        }
        #endregion

        private void dgResults_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
          if (e.ColumnIndex==0)
          {
              Matrix TestMat;
              int currentRow = dgResults.CurrentCell.RowIndex;
              string fileName = dgResults.CurrentCell.Value.ToString();
              String[] seperators = new String[1];
              seperators[0] = @".dat";
              try
              {
                  for (int m = 0; m < 10; m++)//TODO - Find max from sorted list
                  {
                      Vector HistLoaded;
                      BinaryFormatter bf = new BinaryFormatter();
                      FileStream reader = new FileStream(dgResults.Rows[currentRow + m].Cells[0].Value.ToString(), FileMode.Open);
                      TestMat = new Matrix((double[][])bf.Deserialize(reader));
                      reader.Close();
                      //Setting & Loading Histogram
                      HistLoaded = TestMat.GetRowVector(0);
                      if (checkBox1.Checked == true)
                      {
                          HistLoaded[progParametes.Instance.FirstwordToIgnore] = 0;
                      }
                      if (checkBox2.Checked == true)
                      {
                          HistLoaded[progParametes.Instance.SecondwordToIgnore] = 0;
                      }
                      string[] parsedFileName = dgResults.Rows[currentRow + m].Cells[0].Value.ToString().Split(seperators, StringSplitOptions.None);
                      PicBoxArray[m].Load(parsedFileName[0]);
                      PlotHistogram(HistLoaded, m + 1);

                  }
              }
              catch
              {
                  return;
              }
              
          }
        }

        

        
        
        
        //private Vector removeHighest(Vector DataVec)
        //{
        //    double max = 0;
        //    int maxpos = 0;
        //    for(int i=0;i<DataVec.Length;i++)
        //    {
        //        if(DataVec[i]>max)
        //        {
        //            max = DataVec[i];
        //            maxpos = i;
        //        }
        //    }
        //    Vector vec = DataVec.Clone();
        //    vec[maxpos] = 0;
        //    return vec;
        //}

    }
}

//===================================Taking patch with lap=============================
            //Bitmap img = new Bitmap(@"U:\.Windows\Desktop\Winter.bmp");
            //byte[] data = ImageFunctionsAlgorithems.BitMap2Bytes(ref img, 200, 100);
            //byte[] patch1 = new byte[40000];
            //byte[] patch2 = new byte[40000];
            //System.Array.Copy(data, 0, patch1, 0, 40000);
            //System.Array.Copy(data, 280000, patch2, 0, 40000);
            //Bitmap patch1bmp = ImageFunctionsAlgorithems.ByteArray2Bmp(patch1);
            //Bitmap patch2bmp = ImageFunctionsAlgorithems.ByteArray2Bmp(patch2);
            //patch1bmp.Save(@"U:\.Windows\Desktop\Patch1.bmp");
            //patch2bmp.Save(@"U:\.Windows\Desktop\Patch2.bmp");
//=====================================================================================